package com.xpec.c4.service.ioc;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.service.annotations.In;
import com.xpec.c4.service.annotations.Logger;
import com.xpec.c4.service.annotations.Out;

/**
 * Ioc的类管理
 * 
 * @author lipeilin
 * 
 */
public class IocManager {

	private static final Log log = LogFactory.getLog(IocManager.class);

	/**
	 * 已经处理过的类列表
	 */
	//private static HashSet<Class<?>> doneClass = new HashSet<Class<?>>();
	private static Set<Class<?>> doneClass =  Collections.newSetFromMap(new ConcurrentHashMap<Class<?>,Boolean>());
	/**
	 * 带有In注解的类列表
	 */
	private static ConcurrentHashMap<Class<?>,List<Field>> inClass = new ConcurrentHashMap<Class<?>,List<Field>>();

	/**
	 * 带有Out注解的类列表
	 */
	private static ConcurrentHashMap<Class<?>,List<Field>> outClass = new ConcurrentHashMap<Class<?>,List<Field>>();
	
	/**
	 * 带有Log注解的类列表
	 */
	private static ConcurrentHashMap<Class<?>,List<Method>> logClass = new ConcurrentHashMap<Class<?>,List<Method>>();

	/**
	 * 判断此类是否带有In注解
	 * 
	 * @param clazz
	 * @return
	 */
	public static boolean isInClass(Class<?> clazz) {

		// 预注册此类
		registClass(clazz);

		// 如果In的类列表已经存在，直接返回
		if (inClass.containsKey(clazz)) {
			return true;
		}

		return false;

	}

	/**
	 * 判断此类是否带有Out注解
	 * 
	 * @param clazz
	 * @return
	 */
	public static boolean isOutClass(Class<?> clazz) {

		// 预注册此类
		registClass(clazz);

		// 如果In的类列表已经存在，直接返回
		if (outClass.containsKey(clazz)) {
			return true;
		}

		return false;

	}
	
	/**
	 * 判断此类是否带有Log注解
	 * 
	 * @param clazz
	 * @return
	 */
	public static boolean isLogClass(Class<?> clazz) {
		
		// 预注册此类
		registClass(clazz);
		
		// 如果log的类列表已经存在，直接返回
		if (logClass.containsKey(clazz)) {
			return true;
		}
		
		return false;
		
	}
	
	/**
	 * 得到指定class的带有in的fields
	 * @param clazz
	 * @return
	 */
	public static List<Field> getInFields(Class<?> clazz){
		// 预注册此类
		registClass(clazz);
		
		return inClass.get(clazz);
	}
	
	/**
	 * 得到指定class的带有in的fields
	 * @param clazz
	 * @return
	 */
	public static List<Field> getInFields(Class<?> clazz, boolean includeParents){
		List<Field> result = new ArrayList<Field>();
		Class<?> theClass = clazz;
		while (theClass != null) {
			// 预注册此类
			registClass(theClass);
			List<Field> theList = inClass.get(theClass);
			if(theList != null) {
				result.addAll(theList);
			}
			if(!includeParents) {
				break;
			}
			theClass = theClass.getSuperclass();
		}
		return result;
	}
	
	/**
	 * 得到指定class的带有out的fields
	 * @param clazz
	 * @return
	 */
	public static List<Field> getOutFields(Class<?> clazz){
		// 预注册此类
		registClass(clazz);
		
		return outClass.get(clazz);
	}
	
	/**
	 * 得到指定class的带有logger的Methods
	 * @param clazz
	 * @return
	 */
	public static List<Method> getLogMethods(Class<?> clazz){
		// 预注册此类
		registClass(clazz);
		
		return logClass.get(clazz);
	}

	/**
	 * 注册一个处理类。 检查字段的属性
	 * 
	 * @param clazz
	 */
	public static void registClass(Class<?> clazz) {
		// 如果已经处理完了，则不再处理
		if (doneClass.contains(clazz)) {
			return;
		}
		log.debug("regist Class:" + clazz);
		

		// 遍历全部的字段
		List<Field> inField=new ArrayList<Field>();
		List<Field> outField=new ArrayList<Field>();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(In.class)) {
				field.setAccessible(true);
				inField.add(field);
			}
			if (field.isAnnotationPresent(Out.class)) {
				field.setAccessible(true);
				outField.add(field);
			}
		}
		
		//如果有@In的field列表，则添加
		if(inField.size()>0){
			inClass.put(clazz, inField);
		}
		
		//如果有@Out的field列表，则添加
		if(outField.size()>0){
			outClass.put(clazz, outField);
		}
		
		
		// 遍历全部的函数
		List<Method> logMethod=new ArrayList<Method>();
		Method[] methods=clazz.getMethods();
		for (Method method : methods) {
			if (method.isAnnotationPresent(Logger.class)){
				logMethod.add(method);
			}
		}
		
		//如果有@Logger的Method列表，则添加
		if(logMethod.size()>0){
			logClass.put(clazz, logMethod);
		}
		
		doneClass.add(clazz);
	}
	
	/**
	 * 已经注册过的数量
	 * @return
	 */
	public static int registDoneClassSize(){
		return doneClass.size();
	}
	
	/**
	 * 已经注册过带有In的数量
	 * @return
	 */
	public static int registInClassSize(){
		return inClass.size();
	}
	
	/**
	 * 已经注册过带有Out的数量
	 * @return
	 */
	public static int registOutClassSize(){
		return outClass.size();
	}
	
	/**
	 * 已经注册过带有Logger的数量
	 * @return
	 */
	public static int registLogClassSize(){
		return logClass.size();
	}
}
